package infra

import (
	log "github.com/sirupsen/logrus"
	"github.com/tietang/props/kvs"
	"reflect"
)

//基础资源上下结构体
type StarterContext map[string]interface{}

func (s StarterContext) Props() kvs.ConfigSource {
	p := s[KeyProps]
	if p == nil {
		panic("配置未初始化")
	}
	return p.(kvs.ConfigSource)
}

//基础资源启动器接口
type Starter interface {
	//1.系统启动，初始化一些基础资源
	Init(StarterContext)
	//2. 系统基础资源的安装
	Setup(StarterContext)
	//3. 启动基础资源
	Start(StarterContext)
	//启动器是否可阻塞
	StartBlocking() bool
	//4. 资源停止和销毁
	Stop(StarterContext)
	PriorityGroup() PriorityGroup
	Priority() int
}

const (
	SystemGroup         PriorityGroup = 30
	BasicResourcesGroup PriorityGroup = 20
	AppGroup            PriorityGroup = 10

	INT_MAX          = int(^uint(0) >> 1)
	DEFAULT_PRIORITY = 10000
)

//基础空启动器实现,为了方便资源启动器的代码实现
type BaseStarter struct {
}

func (b *BaseStarter) Init(ctx StarterContext)      {}
func (b *BaseStarter) Setup(ctx StarterContext)     {}
func (b *BaseStarter) Start(ctx StarterContext)     {}
func (b *BaseStarter) StartBlocking() bool          { return false }
func (b *BaseStarter) Stop(ctx StarterContext)      {}
func (s *BaseStarter) PriorityGroup() PriorityGroup { return BasicResourcesGroup }
func (s *BaseStarter) Priority() int                { return DEFAULT_PRIORITY }

//启动器注册器
type starterRegister struct {
	nonBlockingStarters []Starter
	blockingStarters    []Starter
}

//启动器注册
func (r *starterRegister) Register(starter Starter) {
	if starter.StartBlocking() {
		r.blockingStarters = append(r.blockingStarters, starter)
	} else {
		r.nonBlockingStarters = append(r.nonBlockingStarters, starter)
	}

	typ := reflect.TypeOf(starter)
	log.Infof("Register starter: %s", typ.String())
}

func (r *starterRegister) AllStarters() []Starter {
	starters := make([]Starter, 0)
	starters = append(starters, r.nonBlockingStarters...)
	starters = append(starters, r.blockingStarters...)
	return starters
}

func GetStarters() []Starter {
	return StarterRegister.AllStarters()
}

type PriorityGroup int

var StarterRegister *starterRegister = new(starterRegister)

func Register(s Starter) {
	StarterRegister.Register(s)
}
